﻿using GMap.NET;
using GMap.NET.MapProviders;
using GMap.NET.WindowsForms;
using GMap.NET.WindowsForms.Markers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GMap.Test
{
   public partial class FormMain : Form
   {
      private MapOperate _mapOperate = MapOperate.None;
      private GMapOverlay _shapeOverlay;
      private List<PointLatLng> _pointsContainer = new List<PointLatLng>();
      private GMapRoute _tempPolyline;
      private GMapPolygon _tempPolygon;
      private HeatMapOverlay _heatMapOverlay;
      private ArrowOverlay _arrowOverlay;
      private GMapCircle _tempCircle;

      public FormMain()
      {
         InitializeComponent();
      }

      private void FormMain_Load(object sender, EventArgs e)
      {
         InitMap();
      }

      private void InitMap()
      {
         mainMap.MapProvider = GMapProviders.GoogleMap;
         mainMap.Manager.Mode = AccessMode.CacheOnly;
         mainMap.DragButton = MouseButtons.Right;
         mainMap.Position = new PointLatLng(30.55, 114.3);
         //mainMap.ShowTileGridLines = true;
         mainMap.MinZoom = 1;
         mainMap.MaxZoom = 6;
         mainMap.Zoom = 3;

         _shapeOverlay = new GMapOverlay("shape");
         _arrowOverlay = new ArrowOverlay("arrows", this.mainMap);
         mainMap.Overlays.Add(_shapeOverlay);
         mainMap.Overlays.Add(_arrowOverlay);

         MapManagerLoader.Instance.Load(@"C:\Users\zxhm0\Desktop\Project\greatmaps\data\DataExp6.gmdb");
      }

      /// <summary>
      /// 点
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void btn_marker_Click(object sender, EventArgs e)
      {
         _mapOperate = MapOperate.Marker;
         ClearTemp();
      }

      /// <summary>
      /// 多段线
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void btn_polyline_Click(object sender, EventArgs e)
      {
         _mapOperate = MapOperate.Polyline;
         ClearTemp();
      }

      /// <summary>
      /// 多边形
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void btn_polygon_Click(object sender, EventArgs e)
      {
         _mapOperate = MapOperate.Polygon;
         ClearTemp();
      }

      /// <summary>
      /// 矩形
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void btn_rectangle_Click(object sender, EventArgs e)
      {
         _mapOperate = MapOperate.Rectangle;
         ClearTemp();
      }

      /// <summary>
      /// 圆
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void btn_circle_Click(object sender, EventArgs e)
      {
         _mapOperate = MapOperate.Circle;
         ClearTemp();
      }

      /// <summary>
      /// 标注
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void btn_label_Click(object sender, EventArgs e)
      {
         _mapOperate = MapOperate.Label;
         ClearTemp();
      }

      /// <summary>
      /// 热力图
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void btn_heatmap_Click(object sender, EventArgs e)
      {
         _mapOperate = MapOperate.Heatmap;
         ClearTemp();
         if (mainMap.Overlays.Contains(_heatMapOverlay))
         {
            mainMap.Overlays.Remove(_heatMapOverlay);
         }
      }

      /// <summary>
      /// 绘制箭头
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void btn_arrow_Click(object sender, EventArgs e)
      {
         _mapOperate = MapOperate.Arrow;
         ClearTemp();
      }

      /// <summary>
      /// 绘制测试包络线
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void btn_envelope_Click(object sender, EventArgs e)
      {
         _mapOperate = MapOperate.Envelope;
         ClearTemp();
      }

      /// <summary>
      /// 清除
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void btn_clear_Click(object sender, EventArgs e)
      {
         _mapOperate = MapOperate.None;
         ClearTemp();
         _shapeOverlay.Markers.Clear();
         _shapeOverlay.Routes.Clear();
         _shapeOverlay.Polygons.Clear();
         _shapeOverlay.Circles.Clear();
         _shapeOverlay.Envelopes.Clear();
         if (mainMap.Overlays.Contains(_heatMapOverlay))
         {
            mainMap.Overlays.Remove(_heatMapOverlay);
         }
         _arrowOverlay.RemoveAll();
      }

      private void mainMap_MouseDown(object sender, MouseEventArgs e)
      {
         var latlng = mainMap.FromLocalToLatLng(e.X, e.Y);
         switch (_mapOperate)
         {
            case MapOperate.Rectangle:
            case MapOperate.Circle:
               if (e.Button == MouseButtons.Left)
               {
                  _pointsContainer.Add(latlng);
               }
               break;
            default:
               break;
         }
      }


      private void mainMap_MouseUp(object sender, MouseEventArgs e)
      {
         var latlng = mainMap.FromLocalToLatLng(e.X, e.Y);
         switch (_mapOperate)
         {
            case MapOperate.Marker:
               if (e.Button == MouseButtons.Left)
               {
                  GMarkerGoogle marker = new GMarkerGoogle(latlng, GMarkerGoogleType.green);
                  _shapeOverlay.Markers.Add(marker);
               }
               break;
            case MapOperate.Polyline:
               if (e.Button == MouseButtons.Left)
               {
                  _pointsContainer.Add(latlng);
               }
               else if (e.Button == MouseButtons.Right)
               {
                  if (_shapeOverlay.Routes.Contains(_tempPolyline))
                  {
                     _shapeOverlay.Routes.Remove(_tempPolyline);
                     _tempPolyline = null;
                  }
                  if (_pointsContainer.Count >= 2)
                  {
                     var polyline = new GMapRoute(_pointsContainer, "polyline");
                     polyline.Stroke = new Pen(Color.Blue, 2);
                     _shapeOverlay.Routes.Add(polyline);
                     _pointsContainer.Clear();
                  }
               }
               break;
            case MapOperate.Polygon:
               if (e.Button == MouseButtons.Left)
               {
                  _pointsContainer.Add(latlng);
               }
               else if (e.Button == MouseButtons.Right)
               {
                  if (_shapeOverlay.Polygons.Contains(_tempPolygon))
                  {
                     _shapeOverlay.Polygons.Remove(_tempPolygon);
                     _tempPolygon = null;
                  }
                  if (_pointsContainer.Count >= 3)
                  {
                     var polygon = new GMapPolygon(_pointsContainer, "polygon");
                     polygon.Fill = new SolidBrush(Color.FromArgb(50, Color.Red));
                     polygon.Stroke = new Pen(Color.Red, 2);
                     _shapeOverlay.Polygons.Add(polygon);
                     _pointsContainer.Clear();
                  }
               }
               break;
            case MapOperate.Rectangle:
               if (e.Button == MouseButtons.Left)
               {
                  if (_shapeOverlay.Polygons.Contains(_tempPolygon))
                  {
                     _shapeOverlay.Polygons.Remove(_tempPolygon);
                     _tempPolygon = null;
                  }
                  if (_pointsContainer.Count == 1)
                  {
                     var tempPoints = new List<PointLatLng>();
                     var start = _pointsContainer[0];
                     tempPoints.Add(start);
                     tempPoints.Add(new PointLatLng(start.Lat, latlng.Lng));
                     tempPoints.Add(latlng);
                     tempPoints.Add(new PointLatLng(latlng.Lat, start.Lng));
                     var rectangle = new GMapPolygon(tempPoints, "rectangle");
                     rectangle.Fill = new SolidBrush(Color.FromArgb(50, Color.Red));
                     rectangle.Stroke = new Pen(Color.Red, 2);
                     _shapeOverlay.Polygons.Add(rectangle);
                     _pointsContainer.Clear();
                  }
                  _mapOperate = MapOperate.None;
               }
               break;
            case MapOperate.Circle:
               if (e.Button == MouseButtons.Left)
               {
                  if (_tempCircle != null)
                  {
                     _shapeOverlay.Circles.Remove(_tempCircle);
                  }
                  if (_pointsContainer.Count == 1)
                  {
                     var center = _pointsContainer[0];
                     var distance = mainMap.MapProvider.Projection.GetDistance(latlng, center) * 1000;
                     var circle = new GMapCircle(center, distance);
                     circle.Fill = new SolidBrush(Color.FromArgb(50, Color.Red));
                     circle.Stroke = new Pen(Color.Red, 2);
                     circle.IsHitTestVisible = true;
                     _shapeOverlay.Circles.Add(circle);
                     _pointsContainer.Clear();
                  }
                  _mapOperate = MapOperate.None;
               }
               break;
            case MapOperate.Label:
               if (e.Button == MouseButtons.Left)
               {
                  var text = new FormLabel().ShowDialogResult();
                  GMarkerCross marker = new GMarkerCross(latlng);
                  marker.ToolTipMode = MarkerTooltipMode.Always;
                  marker.ToolTipText = text;
                  _shapeOverlay.Markers.Add(marker);
               }
               break;
            case MapOperate.Heatmap:
               if (e.Button == MouseButtons.Left)
               {
                  _pointsContainer.Add(latlng);
               }
               else if (e.Button == MouseButtons.Right)
               {
                  if (_pointsContainer.Count > 10)
                  {
                     _heatMapOverlay = new HeatMapOverlay("heatmap", mainMap, _pointsContainer.ToArray());
                     mainMap.Overlays.Add(_heatMapOverlay);
                     _pointsContainer.Clear();
                  }
               }
               break;
            case MapOperate.Arrow:
               if (e.Button == MouseButtons.Left)
               {
                  _pointsContainer.Add(latlng);
                  if (_pointsContainer.Count == 2)
                  {
                     var arrow = new Arrow(_pointsContainer[0], _pointsContainer[1]);
                     _arrowOverlay.Add(arrow);
                     _pointsContainer.Clear();
                  }
               }
               break;
            case MapOperate.Envelope:
               if (e.Button == MouseButtons.Left)
               {
                  _pointsContainer.Add(latlng);
                  if (_pointsContainer.Count == 4)
                  {
                     GMapCircle[] circles = new GMapCircle[_pointsContainer.Count];
                     for (int i = 0; i < _pointsContainer.Count; i++)
                     {
                        double distance = 0;
                        if (i == _pointsContainer.Count - 1)
                        {
                           distance = this.mainMap.MapProvider.Projection.GetDistance(_pointsContainer[i], _pointsContainer[i - 1]) * 1000;
                        }
                        else
                        {
                           distance = this.mainMap.MapProvider.Projection.GetDistance(_pointsContainer[i], _pointsContainer[i+1]) * 1000;
                        }
                        circles[i] = new GMapCircle(_pointsContainer[i],distance);
                     }
                     var envelope = new GMapEnvelope(circles);
                     envelope.Fill = new SolidBrush(Color.FromArgb(50, Color.Red));
                     envelope.Stroke = new Pen(Color.Red, 2);
                     envelope.IsHitTestVisible = true;
                     _shapeOverlay.Envelopes.Add(envelope);
                  }
               }
               break;
            default:
               break;
         }
         if (e.Button == MouseButtons.Right)
         {
            _mapOperate = MapOperate.None;
         }
      }

      private void mainMap_MouseMove(object sender, MouseEventArgs e)
      {
         var latlng = mainMap.FromLocalToLatLng(e.X, e.Y);
         switch (_mapOperate)
         {
            case MapOperate.Polyline:
               if (_shapeOverlay.Routes.Contains(_tempPolyline))
               {
                  _shapeOverlay.Routes.Remove(_tempPolyline);
               }
               if (_pointsContainer.Count >= 1)
               {
                  var tempPoints = new List<PointLatLng>();
                  tempPoints.AddRange(_pointsContainer);
                  tempPoints.Add(latlng);
                  _tempPolyline = new GMapRoute(tempPoints, "tempPolyline");
                  _tempPolyline.Stroke = new Pen(Color.Blue, 2);
                  _shapeOverlay.Routes.Add(_tempPolyline);
               }
               break;
            case MapOperate.Polygon:
               if (_shapeOverlay.Polygons.Contains(_tempPolygon))
               {
                  _shapeOverlay.Polygons.Remove(_tempPolygon);
               }
               if (_pointsContainer.Count >= 2)
               {
                  var tempPoints = new List<PointLatLng>();
                  tempPoints.AddRange(_pointsContainer);
                  tempPoints.Add(latlng);
                  _tempPolygon = new GMapPolygon(tempPoints, "tempPolygon");
                  _tempPolygon.Fill = new SolidBrush(Color.FromArgb(50, Color.Red));
                  _tempPolygon.Stroke = new Pen(Color.Red, 2);
                  _shapeOverlay.Polygons.Add(_tempPolygon);
               }
               break;
            case MapOperate.Rectangle:
               if (_shapeOverlay.Polygons.Contains(_tempPolygon))
               {
                  _shapeOverlay.Polygons.Remove(_tempPolygon);
               }
               if (_pointsContainer.Count == 1)
               {
                  var tempPoints = new List<PointLatLng>();
                  var start = _pointsContainer[0];
                  tempPoints.Add(start);
                  tempPoints.Add(new PointLatLng(start.Lat,latlng.Lng));
                  tempPoints.Add(latlng);
                  tempPoints.Add(new PointLatLng(latlng.Lat, start.Lng));
                  _tempPolygon = new GMapPolygon(tempPoints, "tempPolygon");
                  _tempPolygon.Fill = new SolidBrush(Color.FromArgb(50, Color.Red));
                  _tempPolygon.Stroke = new Pen(Color.Red, 2);
                  _shapeOverlay.Polygons.Add(_tempPolygon);
               }
               break;
            case MapOperate.Circle:
               if (_tempCircle != null)
               {
                  _shapeOverlay.Circles.Remove(_tempCircle);
               }
               if (_pointsContainer.Count == 1)
               {
                  var center = _pointsContainer[0];
                  var distance = mainMap.MapProvider.Projection.GetDistance(latlng, center) * 1000;
                  _tempCircle = new GMapCircle(center, distance);
                  _shapeOverlay.Circles.Add(_tempCircle);
                  if (!this.mainMap.HoldInvalidation)
                  {
                     this.mainMap.Invalidate();
                  }
               }
               break;
            default:
               break;
         }
      }

      private void ClearTemp()
      {
         if (_shapeOverlay.Routes.Contains(_tempPolyline))
         {
            _shapeOverlay.Routes.Remove(_tempPolyline);
         }
         if (_shapeOverlay.Polygons.Contains(_tempPolygon))
         {
            _shapeOverlay.Polygons.Remove(_tempPolygon);
         }
         if (_tempCircle != null)
         {
            _shapeOverlay.Circles.Remove(_tempCircle);
            _tempCircle = null;
         }   
         _tempPolygon = null;
         _tempPolyline = null;
         _pointsContainer.Clear();
      }

      private void mainMap_OnCircleClick(GMapCircle item, MouseEventArgs e)
      {
         Debug.WriteLine(string.Format("{0}:{1}", "DEBUG", "单击了一个圆"));
      }

      private void mainMap_OnCircleDoubleClick(GMapCircle item, MouseEventArgs e)
      {
         Debug.WriteLine(string.Format("{0}:{1}", "DEBUG", "双击了一个圆"));
      }

      private void mainMap_OnEnvelopeClick(GMapEnvelope item, MouseEventArgs e)
      {
         Debug.WriteLine(string.Format("{0}:{1}", "DEBUG", "单击了一个包络线"));
      }

      private void mainMap_OnEnvelopeDoubleClick(GMapEnvelope item, MouseEventArgs e)
      {
         Debug.WriteLine(string.Format("{0}:{1}", "DEBUG", "双击了一个包络线"));
      }

      private void mainMap_OnCircleEnter(GMapCircle item)
      {
         Debug.WriteLine(string.Format("{0}:{1}", "DEBUG", "进入了一个圆"));
      }

      private void mainMap_OnCircleLeave(GMapCircle item)
      {
         Debug.WriteLine(string.Format("{0}:{1}", "DEBUG", "离开了一个圆"));
      }

      private void mainMap_OnEnvelopeEnter(GMapEnvelope item)
      {
         Debug.WriteLine(string.Format("{0}:{1}", "DEBUG", "进入了一个包络线"));
      }

      private void mainMap_OnEnvelopeLeave(GMapEnvelope item)
      {
         Debug.WriteLine(string.Format("{0}:{1}", "DEBUG", "离开了一个包络线"));
      }
   }
}
